"""
风险保证金余额模块
获取系统风险保证金余额信息
"""
import time
from typing import Dict, List, Optional
from datetime import datetime, timedelta
from loguru import logger

try:
    import okx.PublicData as PublicData
except ImportError:
    logger.warning("okx SDK未安装，请运行: pip install okx")
    PublicData = None


class InsuranceFundManager:
    """风险保证金余额管理器"""
    
    # 限速配置：10次/2s
    RATE_LIMIT_REQUESTS = 10
    RATE_LIMIT_WINDOW = 2.0  # 秒
    
    def __init__(self, sandbox: bool = True):
        """
        初始化风险保证金余额管理器
        
        Args:
            sandbox: 是否使用模拟盘，True=模拟盘(1)，False=实盘(0)
        """
        if PublicData is None:
            raise ImportError("okx SDK未安装，请运行: pip install okx")
        
        self.sandbox = sandbox
        flag = "1" if sandbox else "0"
        
        # 初始化OKX公共数据API
        self.public_api = PublicData.PublicAPI(flag=flag)
        
        # 限速控制
        self.request_times: List[float] = []  # 请求时间戳列表
        
        # 数据缓存
        self.insurance_fund_cache: Dict[str, List[Dict]] = {}  # cache_key -> fund_data
        self.cache_expire_time: Dict[str, datetime] = {}  # cache_key -> expire_time
        self.cache_duration = timedelta(hours=1)  # 缓存1小时
        
        logger.info(f"风险保证金余额管理器已初始化 (模式: {'模拟盘' if sandbox else '实盘'})")
    
    def _check_rate_limit(self):
        """
        检查并执行限速
        限速规则：10次/2s (IP)
        """
        now = time.time()
        
        # 移除2秒前的请求记录
        self.request_times = [t for t in self.request_times 
                             if now - t < self.RATE_LIMIT_WINDOW]
        
        # 如果达到限速上限，等待
        if len(self.request_times) >= self.RATE_LIMIT_REQUESTS:
            oldest_request = self.request_times[0]
            wait_time = self.RATE_LIMIT_WINDOW - (now - oldest_request)
            
            if wait_time > 0:
                logger.debug(f"触发限速，等待 {wait_time:.2f} 秒")
                time.sleep(wait_time)
                # 重新计算
                now = time.time()
                self.request_times = [t for t in self.request_times 
                                     if now - t < self.RATE_LIMIT_WINDOW]
        
        # 记录本次请求
        self.request_times.append(now)
    
    def get_insurance_fund(self, inst_type: str,
                          uly: Optional[str] = None,
                          ccy: Optional[str] = None,
                          before: Optional[str] = None,
                          after: Optional[str] = None,
                          limit: int = 100,
                          use_cache: bool = True) -> List[Dict]:
        """
        获取风险保证金余额
        
        Args:
            inst_type: 产品类型
                - MARGIN: 币币杠杆
                - SWAP: 永续合约
                - FUTURES: 交割合约
                - OPTION: 期权
            uly: 标的指数，如 BTC-USD（适用于交割/永续/期权）
            ccy: 币种，如 BTC（适用于币币杠杆）
            before: 请求此时间戳之前的分页内容（毫秒时间戳）
            after: 请求此时间戳之后的分页内容（毫秒时间戳）
            limit: 返回结果数量，最大100，默认100
            use_cache: 是否使用缓存
            
        Returns:
            风险保证金余额信息列表，每条记录包含以下字段：
            - instType: 产品类型
            - total: 风险保证金余额总量
            - details: 详细信息列表
                - amt: 余额
                - balance: 余额
                - ts: 数据返回时间（毫秒时间戳）
        """
        # 生成缓存键
        cache_key = f"{inst_type}_{uly}_{ccy}_{before}_{after}_{limit}"
        
        # 检查缓存
        if use_cache and cache_key in self.insurance_fund_cache:
            expire_time = self.cache_expire_time.get(cache_key)
            if expire_time and datetime.now() < expire_time:
                logger.debug(f"从缓存获取风险保证金余额: {cache_key}")
                return self.insurance_fund_cache[cache_key]
        
        # 执行限速检查
        self._check_rate_limit()
        
        try:
            # 构建请求参数
            params = {
                "instType": inst_type,
                "limit": str(limit)
            }
            if uly:
                params["uly"] = uly
            if ccy:
                params["ccy"] = ccy
            if before:
                params["before"] = before
            if after:
                params["after"] = after
            
            logger.info(f"获取风险保证金余额: {params}")
            result = self.public_api.get_insurance_fund(**params)
            
            # 检查响应
            if result.get("code") != "0":
                error_msg = result.get("msg", "未知错误")
                logger.error(f"获取风险保证金余额失败: {error_msg}")
                raise RuntimeError(f"API错误: {error_msg}")
            
            # 提取数据
            data_list = result.get("data", [])
            logger.info(f"获取风险保证金余额成功: {len(data_list)} 条记录")
            
            # 更新缓存
            if use_cache:
                self.insurance_fund_cache[cache_key] = data_list
                self.cache_expire_time[cache_key] = datetime.now() + self.cache_duration
            
            return data_list
            
        except Exception as e:
            logger.error(f"获取风险保证金余额异常: {e}")
            raise
    
    def get_latest_insurance_fund(self, inst_type: str,
                                  uly: Optional[str] = None,
                                  ccy: Optional[str] = None) -> Optional[Dict]:
        """
        获取最新的风险保证金余额
        
        Args:
            inst_type: 产品类型
            uly: 标的指数
            ccy: 币种
            
        Returns:
            最新的风险保证金余额信息，如果不存在返回None
        """
        data_list = self.get_insurance_fund(inst_type, uly=uly, ccy=ccy, limit=1)
        
        if data_list:
            return data_list[0]
        return None
    
    def get_insurance_fund_details(self, inst_type: str,
                                   uly: Optional[str] = None,
                                   ccy: Optional[str] = None) -> Dict:
        """
        获取风险保证金余额详细信息（包含格式化数据）
        
        Args:
            inst_type: 产品类型
            uly: 标的指数
            ccy: 币种
            
        Returns:
            详细信息字典
        """
        latest = self.get_latest_insurance_fund(inst_type, uly, ccy)
        
        if not latest:
            raise ValueError(f"无法获取风险保证金余额: {inst_type}, uly={uly}, ccy={ccy}")
        
        # 提取详细信息
        details_list = latest.get("details", [])
        formatted_details = []
        
        for detail in details_list:
            ts = int(detail.get("ts", 0))
            timestamp_str = datetime.fromtimestamp(ts / 1000).strftime("%Y-%m-%d %H:%M:%S")
            
            formatted_details.append({
                "amount": float(detail.get("amt", 0)),
                "balance": float(detail.get("balance", 0)),
                "timestamp": timestamp_str,
                "timestamp_ms": ts,
            })
        
        return {
            "inst_type": inst_type,
            "uly": uly,
            "ccy": ccy,
            "total": float(latest.get("total", 0)),
            "details": formatted_details,
        }
    
    def get_swap_insurance_fund(self, uly: str) -> List[Dict]:
        """
        获取永续合约风险保证金余额
        
        Args:
            uly: 标的指数
            
        Returns:
            永续合约风险保证金余额列表
        """
        return self.get_insurance_fund("SWAP", uly=uly)
    
    def get_futures_insurance_fund(self, uly: str) -> List[Dict]:
        """
        获取交割合约风险保证金余额
        
        Args:
            uly: 标的指数
            
        Returns:
            交割合约风险保证金余额列表
        """
        return self.get_insurance_fund("FUTURES", uly=uly)
    
    def get_insurance_fund_history(self, inst_type: str,
                                   uly: Optional[str] = None,
                                   ccy: Optional[str] = None,
                                   days: int = 7) -> List[Dict]:
        """
        获取风险保证金余额历史记录
        
        Args:
            inst_type: 产品类型
            uly: 标的指数
            ccy: 币种
            days: 查询天数，默认7天
            
        Returns:
            历史记录列表
        """
        # 计算时间戳
        now = datetime.now()
        after_time = now - timedelta(days=days)
        after_ts = str(int(after_time.timestamp() * 1000))
        
        return self.get_insurance_fund(
            inst_type,
            uly=uly,
            ccy=ccy,
            after=after_ts,
            limit=100
        )
    
    def compare_insurance_funds(self, inst_type: str, ulys: List[str]) -> List[Dict]:
        """
        比较多个标的的风险保证金余额
        
        Args:
            inst_type: 产品类型
            ulys: 标的指数列表
            
        Returns:
            比较结果列表
        """
        results = []
        
        for uly in ulys:
            try:
                details = self.get_insurance_fund_details(inst_type, uly=uly)
                results.append({
                    "uly": uly,
                    "total": details["total"],
                    "latest_timestamp": details["details"][0]["timestamp"] if details["details"] else None,
                })
            except Exception as e:
                logger.error(f"获取 {uly} 风险保证金余额失败: {e}")
        
        # 按余额排序
        results.sort(key=lambda x: x["total"], reverse=True)
        
        return results
    
    def clear_cache(self, cache_key: Optional[str] = None):
        """
        清除缓存
        
        Args:
            cache_key: 缓存键，如果为None则清除所有缓存
        """
        if cache_key:
            if cache_key in self.insurance_fund_cache:
                del self.insurance_fund_cache[cache_key]
            if cache_key in self.cache_expire_time:
                del self.cache_expire_time[cache_key]
            logger.info(f"已清除 {cache_key} 的缓存")
        else:
            self.insurance_fund_cache.clear()
            self.cache_expire_time.clear()
            logger.info("已清除所有风险保证金余额缓存")
    
    def get_cache_stats(self) -> Dict:
        """
        获取缓存统计信息
        
        Returns:
            缓存统计字典
        """
        total_cached = len(self.insurance_fund_cache)
        valid_cached = sum(1 for key in self.insurance_fund_cache.keys()
                          if key in self.cache_expire_time and
                          datetime.now() < self.cache_expire_time[key])
        
        return {
            "total_cached": total_cached,
            "valid_cached": valid_cached,
            "expired_cached": total_cached - valid_cached,
            "cache_duration_hours": self.cache_duration.total_seconds() / 3600,
        }


# 便捷函数
def get_insurance_fund(inst_type: str, sandbox: bool = True, **kwargs) -> List[Dict]:
    """
    便捷函数：获取风险保证金余额
    
    Args:
        inst_type: 产品类型 (MARGIN/SWAP/FUTURES/OPTION)
        sandbox: 是否使用模拟盘
        **kwargs: 其他参数传递给get_insurance_fund
        
    Returns:
        风险保证金余额信息列表
    """
    manager = InsuranceFundManager(sandbox=sandbox)
    return manager.get_insurance_fund(inst_type, **kwargs)


def get_insurance_fund_details(inst_type: str, uly: Optional[str] = None,
                               ccy: Optional[str] = None, sandbox: bool = True) -> Dict:
    """
    便捷函数：获取风险保证金余额详细信息
    
    Args:
        inst_type: 产品类型
        uly: 标的指数
        ccy: 币种
        sandbox: 是否使用模拟盘
        
    Returns:
        详细信息字典
    """
    manager = InsuranceFundManager(sandbox=sandbox)
    return manager.get_insurance_fund_details(inst_type, uly, ccy)


def compare_insurance_funds(inst_type: str, ulys: List[str], sandbox: bool = True) -> List[Dict]:
    """
    便捷函数：比较多个标的的风险保证金余额
    
    Args:
        inst_type: 产品类型
        ulys: 标的指数列表
        sandbox: 是否使用模拟盘
        
    Returns:
        比较结果列表
    """
    manager = InsuranceFundManager(sandbox=sandbox)
    return manager.compare_insurance_funds(inst_type, ulys)
